package com.uvnos4j.matilda.commons.aop;

import cn.hutool.json.JSONUtil;
import com.uvnos4j.matilda.commons.utils.RequestUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;

/**
 * 统一处理 web 请求日志的切面
 * <p>
 * Description:简单处理，只记录不保存
 * </p>
 *
 * @author Guo.wl
 * @version v1.0.0
 * @since 2020-08-02 09:47:11
 */
@Slf4j
@Aspect
@Component
public class WebLogAspect {

    @Pointcut("execution(public * com.uvnos4j.matilda.*.controller.*.*(..))")
    public void webLog() {
    }

    @Around("webLog()")
    public Object aroundMethod(ProceedingJoinPoint pjp) {
        // 前置通知
        HttpServletRequest request = RequestUtil.getHttpServletRequest();
        // 打印请求相关参数
        log.info("========================================== Start ==========================================");
        log.info("请求IP：{}, URL：[{}] {}.", request.getRemoteAddr(), request.getMethod(), request.getRequestURL());
        log.info("Request 请求参数：{}.", JSONUtil.toJsonStr(request.getParameterMap()));

        MethodSignature signature = (MethodSignature) pjp.getSignature();
        String methodName = signature.getMethod().getName();
        log.info("Method {} 方法参数：{}.", methodName, Arrays.asList(pjp.getArgs()));

        long startTimeMillis = System.currentTimeMillis();
        Object result;
        try {
            // 执行目标方法
            result = pjp.proceed();
            // 后置通知 start
            // 后置通知 end
        } catch (Throwable e) {
            // 异常通知
            log.error("The method {} occurs expection : {}.", methodName, e);
            throw new RuntimeException(e);
        } finally {
            log.info("URI: {}, The method {} cost : {} ms.\r\n最大内存: {}MB  已分配内存: {}MB  已分配内存中的剩余空间: {}MB  最大可用内存: {}MB",
                    request.getRequestURL(), methodName, (System.currentTimeMillis() - startTimeMillis),
                    Runtime.getRuntime().maxMemory() / 1024 / 1024,
                    Runtime.getRuntime().totalMemory() / 1024 / 1024,
                    Runtime.getRuntime().freeMemory() / 1024 / 1024,
                    (Runtime.getRuntime().maxMemory() - Runtime.getRuntime().totalMemory() + Runtime.getRuntime().freeMemory()) / 1024 / 1024);
            // 接口结束后换行，方便分割查看
            log.info("=========================================== End ===========================================" + System.lineSeparator());
        }
        return result;
    }

}